package com.inesv.api.workers;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.inesv.api.baseclasses.BaseApi;
import com.inesv.api.baseclasses.BaseRpcSend;
import com.inesv.api.interfaces.EthMethodDefine;
import com.inesv.api.network.DefaultRPCSend;
import com.inesv.api.utils.HexUtil;
import com.inesv.api.utils.ValidateUtil;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * create by liukeling
 * class name EthApi
 * 以太坊钱包rpcapi的实现类
 */
public class EthApi extends BaseApi implements EthMethodDefine {

    /**
     * 基础的构造函数  传递了钱包服务器的相关信息
     * @param netRPCDefine rpc连接方式
     */
    public EthApi(BaseRpcSend netRPCDefine) {
        super(netRPCDefine);
    }

    /**
     * 根据节点信息构造一个默认的api，使用默认的rpc请求方式
     * @param nodeRPCIP
     * @param nodeRPCPort
     * @param nodeRPCUser
     * @param nodeRPCPassword
     */
    public EthApi(String nodeRPCIP,String nodeRPCPort,String nodeRPCUser,String nodeRPCPassword){
        this(new DefaultRPCSend(nodeRPCIP,nodeRPCPort,nodeRPCUser,nodeRPCPassword));
    }

    /**
     * 根据网络方式和设置初始参数构造一个对象
     * @param sendRPCDefine
     * @param wei
     */
    public EthApi(BaseRpcSend sendRPCDefine,BigDecimal wei,BigDecimal gas, BigDecimal gasPrice){
        super(sendRPCDefine);
        this.WEI = wei;
        this.gas = gas;
        this.gasPrice = gasPrice;
    }

    /**
     * 设置初始参数构造一个对象,rpc连接方式使用默认
     * @param nodeRPCIP        节点ip
     * @param nodeRPCPort      节点端口
     * @param nodeRPCUser      rpc用户
     * @param nodeRPCPassword  rpc密码
     * @param wei              初始化参数wei 与最小单位的转换比率
     * @param gas              初始化rpc参数gas
     * @param gasPrice         初始化rpc参数gasprice
     */
    public EthApi(String nodeRPCIP,String nodeRPCPort,String nodeRPCUser,String nodeRPCPassword,BigDecimal wei,BigDecimal gas, BigDecimal gasPrice){
        super(new DefaultRPCSend(nodeRPCIP,nodeRPCPort,nodeRPCUser,nodeRPCPassword));
        this.WEI = wei;
        this.gas = gas;
        this.gasPrice = gasPrice;
    }
    /**
     * 初始化一些参数 如果构造方法有传相关参数，那么以构造方法为准
     */
    protected void initParam() {
        this.WEI = new BigDecimal("1000000000000000000");
        gas = null;
        gasPrice = null;
    }

    /**
     * 获取节点高度
     * @return  返回节点高度
     */
    public String getHeight() {
        String responseBody = getRPCResult("eth_blockNumber");
        return getRespponseResult(responseBody);
    }

    /**
     * 转账方法
     * @param from   转出账号或地址
     * @param to     转入地址
     * @param value  金额
     * @param password
     * @return
     */
    public String sendTransaction(String from, String to, String value, String password) {
        //先解锁账号
        getRPCResult("personal_unlockAccount",from,password);
        //转账
        Map<String, String> reqMap = new HashMap();
        reqMap.put("from", from);
        reqMap.put("to", to);
        reqMap.put("value", value);
        if(gas != null) reqMap.put("gas", HexUtil.toSixTeenHex(gas.setScale(0,BigDecimal.ROUND_DOWN).toString()));
        if(gasPrice != null) reqMap.put("gasPrice", HexUtil.toSixTeenHex(gasPrice.setScale(0,BigDecimal.ROUND_DOWN).toString()));
        String rpcResponse = getRPCResult("eth_sendTransaction",reqMap);
        return getRespponseResult(rpcResponse);
    }

    /**
     * 根据区块高度获取该高度的流水集合
     * @param height  区块高度  十六进制 带“ox”
     * @return
     */
    public String getTransactionList(String height) {
        String rpcResponse = getRPCResult("eth_getBlockByNumber",height,true);
        String result = getRespponseResult(rpcResponse);
        if(ValidateUtil.isNull(result)) {
            return "[]";
        }
        JSONObject jsonObject = JSONObject.parseObject(result);
        if(jsonObject == null){
            return "[]";
        }
        JSONArray array = jsonObject.getJSONArray("transactions");
        return array == null ? "[]":array.toJSONString();
    }

    /**
     * 获取地址或者账号的余额
     * @param address  地址或账号
     * @return
     */
    public String getBalance(String address) {
        String response = getRPCResult("eth_getBalance",address,"latest");
        return getRespponseResult(response);
    }

    /**
     * 创建钱包地址
     * @param password  创建钱包地址的密码
     * @return
     */
    public String newAddress(String password) {
        String response = getRPCResult("personal_newAccount",password);
        return getRespponseResult(response);
    }

    /**
     * 根据hash获取流水记录
     * @param hash  流水hash
     * @return
     */
    public String getTransactionByHash(String hash) {
        String rpcResponse = getRPCResult("eth_getTransactionByHash",hash);
        return getRespponseResult(rpcResponse);
    }

    @Override
    public String getGasAndGasPrice(String outAddress, String inAddress, String value) {
        if(gas != null && gasPrice != null){
            return HexUtil.toSixTeenHex(gas.multiply(gasPrice).setScale(0,BigDecimal.ROUND_DOWN).toString());
        }
        Map<String, String> reqMap = new HashMap<>();
        reqMap.put("from", outAddress);
        reqMap.put("to", inAddress);
        reqMap.put("value", value);
        if(gas != null)reqMap.put("gas", HexUtil.toSixTeenHex(gas.setScale(0,BigDecimal.ROUND_DOWN).toString()));
        if(gasPrice != null)reqMap.put("gasPrice", HexUtil.toSixTeenHex(gasPrice.setScale(0,BigDecimal.ROUND_DOWN).toString()));
        String gas_get = gas == null?
                getRespponseResult(getRPCResult("eth_estimateGas", reqMap)):
                HexUtil.toSixTeenHex(gas.setScale(0,BigDecimal.ROUND_DOWN).toString());
        String gasPrice_get = gasPrice == null?
                getRespponseResult(getRPCResult("eth_gasPrice", reqMap)):
                HexUtil.toSixTeenHex(gasPrice.setScale(0,BigDecimal.ROUND_DOWN).toString());
        if(gas == null && ValidateUtil.isNull(gas_get)){
             return HexUtil.toSixTeenHex("0");
        }
        if(ValidateUtil.isNull(gasPrice_get)){
            return HexUtil.toSixTeenHex(new BigDecimal("90000").multiply(gas).toString());
        }
        BigDecimal gasGet = new BigDecimal(HexUtil.toTenHex(gas_get));
        BigDecimal gasPriceGet = new BigDecimal(HexUtil.toTenHex(gasPrice_get));
        return HexUtil.toSixTeenHex(gasGet.multiply(gasPriceGet).setScale(0,BigDecimal.ROUND_DOWN).toString());
    }

    /**
     * 根据需要的信息，调用rpc方法，获取结果
     * @param method
     * @param params
     * @return
     */
    protected String getRPCResult(String method,Object... params){
        String requestBody = new String(netRPCDefine.prepareRequest(method,params));
        return netRPCDefine.generateRequest(requestBody,netRPCDefine.getNodeUri());
    }

    /**
     * 根据rpc返回结果获取result的json数据
     * @param rpcResponse  rpc返回结果
     * @return  结果中result的json数据
     */
    protected String getRespponseResult(String rpcResponse){
        if(!ValidateUtil.isNull(rpcResponse)){
            JSONObject jsonObject = JSONObject.parseObject(rpcResponse);
            if(jsonObject.containsKey("result")){
                return jsonObject.getString("result");
            }
        }
        return "";
    }
}
